#include <SimulationManager.h>
#include <EDesignerCore.h>

#include <iostream>

#include <Functions.h>

class SimulationThread : public OpenThreads::Thread
{
public:
    SimulationThread()
    {
        m_stop = false;
        m_condition1 = new OpenThreads::Condition;
        m_mutex1 = new OpenThreads::Mutex;
        m_condition2 = new OpenThreads::Condition;
        m_mutex2 = new OpenThreads::Mutex;

    }
    virtual ~SimulationThread()
    {

    }
    virtual void run()
    {
        m_stop = false;
        while (1)
        {
            //std::cout<<"thread update"<<std::endl;
            m_manager->update();

            if( m_manager->getIsWaitFrameEnd() == true)
            {

                m_condition1->signal();
                std::cout<<"thread signal"<<std::endl;

                m_mutex2->lock();
                std::cout<<"thread wait"<<std::endl;
                m_condition2->wait(m_mutex2);
                std::cout<<"thread wait out"<<std::endl;
                m_mutex2->unlock();


                /*m_mutex1->lock();
                m_mutex1->unlock();*/
            }

            if(m_stop == true)
            {
                break;
            }
        }

    }
    virtual int cancel()
    {
        m_stop = true;
        return OpenThreads::Thread::cancel();
    }


    SimulationManager* m_manager;
    bool m_stop;
    OpenThreads::Condition* m_condition1;
    OpenThreads::Mutex* m_mutex1;
    OpenThreads::Condition* m_condition2;
    OpenThreads::Mutex* m_mutex2;

};


SimulationManager::SimulationManager() : QObject()
{
    m_timer = new QTimer(this);
    QObject::connect(m_timer, SIGNAL(timeout()), this, SLOT(slotTimer()));
    //setRunInMainThread();
    SimulationThread* simThread = new SimulationThread();
    m_thread = simThread;
    simThread->m_manager = this;

    m_waitFrameEnd = false;

    m_currentMode = -1;

    m_buttonStart = true;
    m_buttonPause = false;
    m_buttonStop = false;

    m_state = 1;
    m_timerCount = 0;
}

SimulationManager::~SimulationManager()
{
    delete m_thread;
    delete m_timer;
}

void SimulationManager::addSimulationObject(QSharedPointer<SimulationObject> simObj)
{
    m_simObjList.push_back(simObj);
}

void SimulationManager::setRunAsSingleThread()
{
    m_timer->stop();
    //this->moveToThread(m_thread);
    m_thread->start();
    m_currentMode = 1;
}

void SimulationManager::setRunInMainThread()
{
    m_thread->cancel();
    m_timer->start(10);
    m_currentMode = 0;
    m_preTime = QDateTime::currentDateTime();
    m_timerCount = 0;
}

void SimulationManager::waitUpdateEndAndStopSim()
{
    if(m_currentMode != 1) return;
    m_waitFrameEnd = true;

    SimulationThread* st = dynamic_cast<SimulationThread*>(m_thread);
    st->m_mutex1->lock();

    /**/
    std::cout<<"manager wait"<<std::endl;
    st->m_condition1->wait(st->m_mutex1);
    std::cout<<"manager wait out"<<std::endl;



}

void SimulationManager::stopWaitUpdateEnd()
{
    if(m_currentMode != 1) return;
    m_waitFrameEnd = false;
    SimulationThread* st = dynamic_cast<SimulationThread*>(m_thread);

    st->m_condition2->signal();
    std::cout<<"manager signal"<<std::endl;

    st->m_mutex1->unlock();
}

bool SimulationManager::getIsWaitFrameEnd()
{
    return m_waitFrameEnd;
}

void SimulationManager::update()
{
    QDateTime currentTime = QDateTime::currentDateTime();
    //std::cout<<"SimulationManager::update"<<m_preTime.msecsTo(currentTime)<<std::endl;
    m_preTime = currentTime;
    int interval = (int)(m_preTime.msecsTo(currentTime));
    //std::cout<<"SimulationManager::update"<<interval<<std::endl;


    for(int i = 0; i < m_simObjList.size(); i++)
    {
        m_simObjList.at(i)->setTimeInterval(interval/1000.0);
    }
    if(m_buttonStart == true && m_buttonPause == false && m_buttonStop == false)
    {
        if(m_state == 3)
        {
            //recover the state before sim
            EDesignerCore::instance()->loadSimulationState();
            //updatePausing to update
            callSimObjListUpdatePausingToUpdate();
        }
        else if(m_state == 2)
        {
            //recover the state before sim
            EDesignerCore::instance()->loadSimulationState();
            //updateRunning to update
            callSimObjListUpdatePausingToUpdate();
        }
        callSimObjListUpdate();
        m_state = 1;
    }
    else if(m_buttonStart == false && m_buttonPause == true && m_buttonStop == true)
    {
        if(m_state == 1)
        {
            //save the state before start simulation
            EDesignerCore::instance()->saveSimulationState();
            //update to updateRunning
            callSimObjListUpdateToUpdateRunning();
        }
        else if(m_state == 3)
        {
            //pausing to updateRunning
            callSimObjListUpdatePausingToUpdateRunning();
        }

        callSimObjListUpdateRunning();
        m_state = 2;
    }
    else if(m_buttonStart == true && m_buttonPause == false && m_buttonStop == true)
    {
        if(m_state == 1)
        {
            //update to updatePausing
            callSimObjListUpdateToUpdatePausing();
        }
        else if(m_state == 2)
        {
            //updateRunning to updatePausing
            callSimObjListUndateRunningToUpdatePausing();
        }

        callSimobjListUpdatePausing();
        m_state = 3;
    }

}

void SimulationManager::startSimulation()
{
    m_buttonStart = false;
    m_buttonPause = true;
    m_buttonStop = true;

}

void SimulationManager::stopSimulation()
{
    m_buttonStart = true;
    m_buttonPause = false;
    m_buttonStop = false;

}

void SimulationManager::pauseSimulation()
{
    m_buttonStart = true;
    m_buttonPause = false;
    m_buttonStop = true;

}

void SimulationManager::slotTimer()
{

    m_timerCount++;

    update();
}

void SimulationManager::callSimObjListUpdatePausingToUpdate()
{
    for(int i = 0; i < m_simObjList.size(); i++)
    {
        m_simObjList.at(i)->updatePausingToUpdate();
    }
}

void SimulationManager::callSimObjListUpdateRunningToUpdate()
{
    for(int i = 0; i < m_simObjList.size(); i++)
    {
        m_simObjList.at(i)->updateRunningToUpdate();
    }

}

void SimulationManager::callSimObjListUpdateToUpdateRunning()
{
    for(int i = 0; i < m_simObjList.size(); i++)
    {
        m_simObjList.at(i)->updateToUpdateRunning();
    }
}

void SimulationManager::callSimObjListUpdatePausingToUpdateRunning()
{
    for(int i = 0; i < m_simObjList.size(); i++)
    {
        m_simObjList.at(i)->updatePausingToUpdateRunning();
    }
}

void SimulationManager::callSimObjListUpdateToUpdatePausing()
{
    for(int i = 0; i < m_simObjList.size(); i++)
    {
        m_simObjList.at(i)->updateToUpdatePausing();
    }
}

void SimulationManager::callSimObjListUndateRunningToUpdatePausing()
{
    for(int i = 0; i < m_simObjList.size(); i++)
    {
        m_simObjList.at(i)->undateRunningToUpdatePausing();
    }
}

void SimulationManager::callSimObjListUpdate()
{
    for(int i = 0; i < m_simObjList.size(); i++)
    {
        m_simObjList.at(i)->update();
    }
}

void SimulationManager::callSimObjListUpdateRunning()
{
    for(int i = 0; i < m_simObjList.size(); i++)
    {
        m_simObjList.at(i)->updateRunning();
    }
}

void SimulationManager::callSimobjListUpdatePausing()
{
    for(int i = 0; i < m_simObjList.size(); i++)
    {
        m_simObjList.at(i)->updatePausing();
    }
}

//void SimulationManager::doWork()
//{
//}
